#include <muduo/base/Logging.h>

#include <muduo/base/CurrentThread.h>
#include <muduo/base/Timestamp.h>
#include <muduo/base/TimeZone.h>

#include <errno.h>
#include <stdio.h>
#include <string.h>

#include <sstream>

namespace muduo
{

/*
class LoggerImpl
{
 public:
  typedef Logger::LogLevel LogLevel;
  LoggerImpl(LogLevel level, int old_errno, const char* file, int line);
  void finish();

  Timestamp time_;
  LogStream stream_;
  LogLevel level_;
  int line_;
  const char* fullname_;
  const char* basename_;
};
*/

	__thread char t_errnobuf[512]; // 在每一个线程里面，都会出现这些个玩意
	__thread char t_time[32];
	__thread time_t t_lastSecond;

	const char* strerror_tl(int savedErrno)
	{
		return strerror_r(savedErrno, t_errnobuf, sizeof t_errnobuf);
	}

	Logger::LogLevel initLogLevel()
	{
		if (::getenv("MUDUO_LOG_TRACE"))
			return Logger::TRACE;
		else if (::getenv("MUDUO_LOG_DEBUG"))
			return Logger::DEBUG;
		else
			return Logger::INFO;
	}

	Logger::LogLevel g_logLevel = initLogLevel(); // 好吧，果然是全局的东西

	const char* LogLevelName[Logger::NUM_LOG_LEVELS] =
	{
		"TRACE ",
		"DEBUG ",
		"INFO  ",
		"WARN  ",
		"ERROR ",
		"FATAL ",
	};

	// helper class for known string length at compile time
	class T // 好吧，据说是一个辅助类
	{
	public:
		T(const char* str, unsigned len)
			: str_(str)
			, len_(len)
		{
			assert(strlen(str) == len_);
		}

		const char* str_;
		const unsigned len_;
	};

	inline LogStream& operator<<(LogStream& s, T v)
	{
		s.append(v.str_, v.len_); // 就是往里面添加string，是吧！
		return s;
	}

	inline LogStream& operator<<(LogStream& s, const Logger::SourceFile& v)
	{
		s.append(v.data_, v.size_); // 往里面添加源文件的信息
		return s;
	}

	void defaultOutput(const char* msg, int len)
	{
		size_t n = fwrite(msg, 1, len, stdout);
		//FIXME check n
		(void)n;
	}

	void defaultFlush()
	{
		fflush(stdout);
	}

	Logger::OutputFunc g_output = defaultOutput; // 默认的输出函数，默认往标准输出里面输出
	Logger::FlushFunc g_flush = defaultFlush; // 默认的刷新，直接往标准输出里面刷新
	TimeZone g_logTimeZone; // 时区

}

using namespace muduo;

Logger::Impl::Impl(LogLevel level, int savedErrno, const SourceFile& file, int line)
	: time_(Timestamp::now())
	, // now() stream_()
	, level_(level)
	, line_(line)
	, basename_(file)
{
	formatTime();
	CurrentThread::tid(); 
	stream_ << T(CurrentThread::tidString(), CurrentThread::tidStringLength()); // 首先记录线程id
	stream_ << T(LogLevelName[level], 6); // 记录日志的层次
	if (savedErrno != 0)
	{
		stream_ << strerror_tl(savedErrno) << " (errno=" << savedErrno << ") ";
	}
}

void Logger::Impl::formatTime()
{
	int64_t microSecondsSinceEpoch = time_.microSecondsSinceEpoch();
	time_t seconds = static_cast<time_t>(microSecondsSinceEpoch / Timestamp::kMicroSecondsPerSecond);
	int microseconds = static_cast<int>(microSecondsSinceEpoch % Timestamp::kMicroSecondsPerSecond);
	if (seconds != t_lastSecond)
	{
		t_lastSecond = seconds;
		struct tm tm_time;
		if (g_logTimeZone.valid())
		{
			tm_time = g_logTimeZone.toLocalTime(seconds);
		}
		else
		{
			::gmtime_r(&seconds, &tm_time); // FIXME TimeZone::fromUtcTime
		}

		int len = snprintf(t_time,
			sizeof(t_time),
			"%4d%02d%02d %02d:%02d:%02d",
			tm_time.tm_year + 1900,
			tm_time.tm_mon + 1,
			tm_time.tm_mday,
			tm_time.tm_hour,
			tm_time.tm_min,
			tm_time.tm_sec);
		assert(len == 17); (void)len;
	}

	if (g_logTimeZone.valid())
	{
		Fmt us(".%06d ", microseconds);
		assert(us.length() == 8);
		stream_ << T(t_time, 17) << T(us.data(), 8);
	}
	else
	{
		Fmt us(".%06dZ ", microseconds);
		assert(us.length() == 9);
		stream_ << T(t_time, 17) << T(us.data(), 9);
	}
}

void Logger::Impl::finish()
{
	stream_ << " - " << basename_ << ':' << line_ << '\n';
}

Logger::Logger(SourceFile file, int line)
	: impl_(INFO, 0, file, line)
{
}

Logger::Logger(SourceFile file, int line, LogLevel level, const char* func)
	: impl_(level, 0, file, line)
{
	impl_.stream_ << func << ' ';
}

Logger::Logger(SourceFile file, int line, LogLevel level)
	: impl_(level, 0, file, line)
{
}

Logger::Logger(SourceFile file, int line, bool toAbort)
	: impl_(toAbort ? FATAL : ERROR, errno, file, line)
{
}

Logger::~Logger()
{
	impl_.finish();
	const LogStream::Buffer& buf(stream().buffer());
	g_output(buf.data(), buf.length());
	if (impl_.level_ == FATAL)
	{
		g_flush();
		abort();
	}
}

void Logger::setLogLevel(Logger::LogLevel level)
{
	g_logLevel = level;
}

void Logger::setOutput(OutputFunc out) // 这个玩意是一个函数吧！
{
	g_output = out;
}

void Logger::setFlush(FlushFunc flush) // 用于刷新的函数
{
	g_flush = flush;
}

void Logger::setTimeZone(const TimeZone& tz) // 设置时区
{
	g_logTimeZone = tz;
}
